package com.zhang.learn.io.nio.buffer;

import org.junit.Test;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;

/**
 * @author zhanghaolian
 * @Description 缓冲器底层就是数组实现的
 * 根据数据类型不同，提供了对应类型的缓冲器(一共7种)，除了boolean类型以外
 *
 * ByteBuffer
 * CharBuffer
 * ShortBuffer
 * IntBuffer
 * LongBuffer
 * FloatBuffer
 * DoubleBuffer
 *
 * 上述缓冲区的管理方式几乎相同
 *
 * 创建: 通过allocate()
 *
 * 缓冲区当中两个存取数据的核心方法：
 * put();
 * get();
 *
 * 缓冲区中的核心参数：
 * capacity:容量，一旦申明就不能改变。
 * limit:界限，缓冲区中可以操作的的数据的大小（limit后面的数据部门读写）。
 * position：位置，缓冲区正在操作数据的位置，position=<limit position=<capacity
 *
 * mark():标记，可以记录position的位置，并通过reset()恢复到mark的位置
 *
 * hasRemaining():判断缓冲区中是否还有剩余的数据
 * remaining():获取缓冲区中剩余的数据的数量
 *
 * 直接缓冲区与非直接缓冲区
 *  非直接缓冲区:通过allocate()方法创建的缓冲区，是建立在jvm的内存中
 *  直接缓冲区:通过allocateDirect()方法创，可以将缓冲区建立在操作系统内存中，在某种情况下是可以提高效率
 *
 * @ClassName BufferTest
 * @date 2021/2/10 21:18
 */
public class BufferTest {

    /**
     * ByteBuffer
     * @throws UnsupportedEncodingException
     */
    @Test
    public void test1() throws UnsupportedEncodingException {
        // 1、分配一个指定大小的缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(5);
        System.out.println("----------------allocate()--------------------");
        System.out.println("capacity: " + buffer.capacity());
        System.out.println("position: " + buffer.position());
        System.out.println("limit: " + buffer.limit());

        // 2、使用put()方法写数据
        buffer.put("12345".getBytes(StandardCharsets.UTF_8));
        System.out.println("----------------buffer存数据存满以后()--------------------");
        System.out.println("capacity: " + buffer.capacity());
        System.out.println("position: " + buffer.position());
        System.out.println("limit: " + buffer.limit());

        // 3、切换到读数据模式，position位置指到0，limit位置指到原position的位置
        buffer.flip();
        System.out.println("----------------切换到读数据模式()--------------------");
        System.out.println("capacity: " + buffer.capacity());
        System.out.println("position: " + buffer.position());
        System.out.println("limit: " + buffer.limit());

        // 4、使用get()方法读取数据
        byte[] dst = new byte[buffer.limit()];
        buffer.get(dst);
        System.out.println(new String(dst,"UTF-8"));
        System.out.println("----------------使用get()读数据--------------------");
        System.out.println("capacity: " + buffer.capacity());
        System.out.println("position: " + buffer.position());
        System.out.println("limit: " + buffer.limit());

        // 5、rewind() 课重复读数据
        buffer.rewind();
        System.out.println(new String(dst,"UTF-8"));
        System.out.println("----------------rewind()读数据--------------------");
        System.out.println("capacity: " + buffer.capacity());
        System.out.println("position: " + buffer.position());
        System.out.println("limit: " + buffer.limit());

        // 6、clear()清空缓冲区，回到最初状态，但是缓冲区中的数据依然存在，只是这些数据处在被遗忘的状态
        buffer.clear();
        System.out.println("----------------clear()清空缓冲区--------------------");
        System.out.println("capacity: " + buffer.capacity());
        System.out.println("position: " + buffer.position());
        System.out.println("limit: " + buffer.limit());
    }

    @Test
    public void testMark() {
        ByteBuffer bf = ByteBuffer.allocate(1024);
        String str = "abcde";
        bf.put(str.getBytes());
        bf.flip();

        byte[] tempByte = new byte[bf.limit()];
        bf.get(tempByte,0,2);
        System.out.println(new String(tempByte));
        System.out.println(bf.position());

        //使用mark标记当前position位置
        bf.mark();
        System.out.println(bf.position());

        bf.get(tempByte,2,2);
        System.out.println(new String(tempByte));
        System.out.println(bf.position());

        // 使用reset恢复到mark标记的位置
        bf.reset();
        System.out.println(bf.position());

        // 判断缓冲区中是否还有剩余的数据
        if(bf.hasRemaining()) {
            // 获取缓冲区中剩余的数据的数量
            System.out.println(bf.remaining());
        }

    }

}